/* 
 * Copyright (C) 2006-2013 普信恒业科技发展（北京）有限公司.
 * 本系统是商用软件,未经授权擅自复制或传播本程序的部分或全部将是非法的.
============================================================
 * FileName: SequencesElementType.java 
 * Created: [Jun 6, 2013 2:48:47 PM] by Administrator 
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
============================================================ 
 * ProjectName: mspl_dev 
 * Description: 
==========================================================*/

package com.creditease.modules.coderule.elementype;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.creditease.modules.coderule.CodeRuleUtils;
import com.creditease.modules.coderule.cycle.ICycleElement;
import com.creditease.modules.coderule.dao.CodeRuleDao;
import com.creditease.modules.coderule.factory.ICycleFactory;
import com.creditease.sframe.exception.UncheckedException;

/** 
 * Description: 序列号元素类型，不同于常量和变量，他需要根据一系的属性的进行值的获取，
 * 				在获取值时，不但要判断循环周期，还要变更当前值
 * @author chens
 * @version 1.0
 * <pre>
 * Modification History: 
 * Date         Author      Version     Description 
------------------------------------------------------------------
 * Jun 6, 2013    Administrator       1.0        1.0 Version 
 * </pre>
 */
@Service("BET_003")
public class SequencesElementType implements IElementType {

	private final static String serialslock = "lock";//序列锁
	@Autowired
	private ICycleFactory cycleFactory;				 //序列循环处理工厂
	@Autowired
	private CodeRuleDao codeRuleDao;					 //操作数据的DAO
	/* (non-Javadoc)
	 * @see com.creditease.mspl.coderule.elementype.IElementType#getElementTypeString(java.util.Map)
	 */
	@SuppressWarnings("unchecked")
	public String getElementTypeString(Map<String, String> value_separator) {
		// TODO Auto-generated method stub
		String serialStr = "";
		synchronized(serialslock){
			String serialId = value_separator.get("SERIAL_ID");
			//根据序列ID获取序列属性对象，以Map对象返回
			HashMap serialMap = getSerials(serialId);
			if(serialMap != null && serialMap.size() > 0 ){
				updateCurrentValueWithCycle(serialMap);
				//之所以又获取一次，是因为前一步已经把数据库更新了
				serialMap = getSerials(serialId);
				//获取序列值
				serialStr += getSequenceValue(value_separator,serialMap);
				//获取分隔符、分隔符如果为null就不要追加了
				if(StringUtils.hasText(value_separator.get("ELEMENT_SEPARATOR"))){
					serialStr += value_separator.get("ELEMENT_SEPARATOR");
				}
				return serialStr;
			}else{
				throw new UncheckedException("MSPL_CR_0001_04");
			}
		}
	}
	/**
	 * Description: 根据修改时间判断 重置序列值，更新修改时间
	 * @param
	 * @return void
	 * @throws
	 * @Author chens
	 * Create Date: Jun 6, 2013 3:54:31 PM
	 */
	@SuppressWarnings("unchecked")
	private void updateCurrentValueWithCycle(HashMap serialMap){
		if(serialMap != null){
			Date updateTime = new Date();
			if(serialMap.get("UPDATE_TIME") != null){
				updateTime = (Date)serialMap.get("UPDATE_TIME");
			}else{
				throw new UncheckedException("该序号属性记录的更新字段[update_time]为空，数据库数据错误！");
			}
			String elementCycle = (String)serialMap.get("ELEMENT_CYCLE");
			if(StringUtils.hasText(elementCycle)){
				ICycleElement cycleElement = cycleFactory.creatCycleElement(elementCycle);
				//判断是否需要在循环之内,不在循环之内，重置序列号，并且更新修改时间
				if(!cycleElement.isWarrantyCycle(updateTime)){
					//重置序列号，更新修改时间
					updateCurrentValueUpateTime((String)serialMap.get("ID"));
				}
			}
			//没有else，不再做任何处理。因为如果读取不到流水号循环周期代表不循环,也不需要抛出异常。以下将不再有代码。
		}
	}
	/**
	 * Description: 获取序列值
	 * @param
	 * @return String
	 * @throws
	 * @Author Administrator
	 * Create Date: Jun 6, 2013 4:36:23 PM
	 */
	@SuppressWarnings("unchecked")
	private String getSequenceValue(Map<String,String> value_separator,HashMap serialMap){
		String sequenceStr = "";
		if(value_separator != null){
			String digits = value_separator.get("ELEMENT_VALUE");
			return CodeRuleUtils.supplementDigits(getNextNumber(serialMap),digits);
		}
		return sequenceStr;
	}
	/**
	 * Description: 计算序列值=当前值+步长
	 * @param
	 * @return String
	 * @throws
	 * @Author Administrator
	 * Create Date: Jun 6, 2013 4:40:25 PM
	 */
	@SuppressWarnings("unchecked")
	private String getNextNumber(HashMap mapSerial){
		String result = "";
		//获取主键
		String id = (String)mapSerial.get("ID");
		//获取当前值
		BigDecimal currentValue = (BigDecimal)mapSerial.get("CURRENT_VALUE");
		//获取步长值
		BigDecimal stepValue = (BigDecimal)mapSerial.get("STEP_VALUE");
		//判断当前值是否为空
		if(currentValue == null || !StringUtils.hasText(String.valueOf(currentValue))){
			//如果当前值为空，则获取初始值
			BigDecimal initValue = (BigDecimal)mapSerial.get("INIT_VALUE");
			result = String.valueOf(initValue);
		}else{
			//如果当前值不为空，则返回 当前值+步长
			result = String.valueOf(currentValue.add(stepValue));
		}
		//更新当前值到数据库
		updateCurrentValue(id,result);
		return result;
	}
	/**
	 * Description: 根据serialsId得到一个Serials数据的list
	 * @param serialsId主键 
	 * @return HashMap
	 * @throws
	 * @Author Administrator
	 * Create Date: Jun 6, 2013 5:05:49 PM
	 */
	@SuppressWarnings("unchecked")
	private HashMap getSerials(String serialId) {
		Map map = new HashMap();
		map.put("id", serialId);
		return (HashMap) codeRuleDao.querySerials(map);
		
	}
	/**
	 * Description: 更新smp_res_serials表的当前值为null,且updateTime字段为当前值(new Date())
	 * @param serialsId主键 
	 * @return void
	 * @throws
	 * @Author chens
	 * Create Date: Jun 6, 2013 5:13:35 PM
	 */
	@SuppressWarnings("unchecked")
	private void updateCurrentValueUpateTime(String serialId) {
		Map map = new HashMap();
		map.put("id", serialId);
		map.put("update_time", new Date());
		codeRuleDao.updateSerials(map);
	}
	
	/**
	 * Description: 更新smp_res_serials表的当前值
	 * @param serialsId主键 
	 * @return void
	 * @throws
	 * @Author Administrator
	 * Create Date: Jun 6, 2013 5:17:17 PM
	 */
	@SuppressWarnings("unchecked")
	public void updateCurrentValue(String serialId,String currentValue){
		Map map = new HashMap();
		map.put("id", serialId);
		map.put("current_value", currentValue);
		codeRuleDao.updateSerials(map);
	}
}
